home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / ae.lha / ae / AE / ae-sparc.h < prev    next >
C/C++ Source or Header  |  1990-02-28  |  13KB  |  454 lines

  1. /* AE program profiling system.
  2.    Machine-specific definitions for SPARC processors.
  3.    Copyright (C) 1990 by James R. Larus. (larus@cs.wisc.edu)
  4.  
  5.    AE and AEC are free software; you can redistribute it and/or modify it
  6.    under the terms of the GNU General Public License as published by the
  7.    Free Software Foundation; either version 1, or (at your option) any
  8.    later version.
  9.  
  10.    AE and AEC are distributed in the hope that it will be useful, but
  11.    WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.    General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with GNU CC; see the file COPYING.  If not, write to James R.
  17.    Larus, Computer Sciences Department, University of Wisconsin--Madison,
  18.    1210 West Dayton Street, Madison, WI 53706, USA or to the Free
  19.    Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21.  
  22. /* $Header: /var/home/larus/AE/AE/RCS/ae-sparc.h,v 2.0 90/02/09 17:21:58 larus Exp Locker: larus $ */
  23.  
  24.  
  25. /* Define the base and bounds of the AE buffer that accumulates events in
  26.    the executing program. */
  27.  
  28.  
  29. /* The pointer to the AE Buffer can either be in a register or in a
  30.    variable stored in memory.  If it is in a register, AE_BUFFER_REG
  31.    contains the register's name, as a string.  If it is in memory,
  32.    AE_BUFFER_VAR contains the variable's name as a string.
  33.    MAKE_AE_BUFFER_POINTER returns an rtx expression for this pointer. */
  34.  
  35. /* On SPARC, we use base and bounds registers (%g4 and %g6,
  36.    respectively). */
  37.  
  38. #define AE_BUFFER_REG "%g4"
  39. #undef AE_BUFFER_VAR
  40.  
  41. #define MAKE_AE_BUFFER_POINTER() gen_rtx (REG, Pmode, 4) /* 4 = %g4 */
  42.  
  43.  
  44. /* The end of the AE Buffer can either be pointed to by a register or
  45.    by a variable stored in memory.  If it is in a register,
  46.    AE_BUFFER_BOUND_REG contains the register's name, as a string.  If it
  47.    is in memory, AE_BUFFER_BOUND_VAR contains the variable's name as a
  48.    string.  MAKE_AE_BOUND_POINTER returns an rtx expression for this
  49.    pointer. */
  50.  
  51. #define AE_BUFFER_BOUND_REG "%g6"
  52. #undef AE_BUFFER_BOUND_VAR
  53.  
  54. #define MAKE_AE_BOUND_POINTER()     gen_rtx (REG, Pmode, 6)
  55.  
  56.  
  57. /* Alternatively, the end of the AE buffer can be a fixed distance
  58.    from the top of the stack. */
  59.  
  60. #undef STACK_TOP
  61. #undef AE_BUFFER_STACK_OFFSET
  62.  
  63.  
  64. /* Size of AE buffer (bytes). */
  65.  
  66. #define AE_BUFFER_SIZE 0x100000    /* 1MB */
  67.  
  68.  
  69. /* Size of a stack frame for the routine AE_START. */
  70.  
  71. /* Need a 16 word window save area for SPARC */
  72.  
  73. #define AE_START_FRAME_SIZE (16 * sizeof (int))
  74.  
  75.  
  76. /* Name of stack pointer register. */
  77.  
  78. #define SP_REG "%sp"
  79.  
  80.  
  81.  
  82. /* One plus maximum number of instructions combine by peephole optimizer. */
  83.  
  84. #define MAX_PEEP 3
  85.  
  86.  
  87. /* Return non-zero if register number REGNO can be defined upon
  88.    function entry. */
  89.  
  90. #define REGISTER_DEFINED_IN_CALL(REGNO) ((REGNO) == STACK_POINTER_REGNUM \
  91.                      || (REGNO) == FRAME_POINTER_REGNUM \
  92.                      || ((REGNO) >= 24 && (REGNO) <= 31))
  93.  
  94.  
  95. /* Define the characters that proceed comments and assembler directives. */
  96.  
  97. #define ASM_COMMENT_CHAR '!'
  98.  
  99. #define ASM_DIRECTIVE_CHAR '.'
  100.  
  101.  
  102. /* Define the number of delayed instructions after a jump, conditional jump,
  103.    or call instruction.  Do not define these values if the instructions have
  104.    no delays or the assembler hides them by doing code reorganization. */
  105.  
  106. #define JUMP_DELAY_SLOTS 1
  107.  
  108. #define CJUMP_DELAY_SLOTS 1
  109.  
  110. #define CALL_DELAY_SLOTS 1
  111.  
  112.  
  113. /* The size of most assembly instructions (in bytes). */
  114.  
  115. #define STD_ASM_INSN_LENGTH 4
  116.  
  117.  
  118. /* Set of instruction-size pairs for instructions whose size is not
  119.    standard.  The table must be sorted by instruction name. */
  120.  
  121. #undef ASM_INSN_SIZE_EXCEPTIONS
  122.  
  123.  
  124. /* Return non-zero if the assembly instruction is a branch that does
  125.    not execute its (normally) delayed slot instruction. */
  126.  
  127. #define BRANCH_IS_ANNULED(ASM_INSN) substring (ASM_INSN, ",a ")
  128.  
  129.  
  130. /* Return a pointer to the function name if an assembly instruction is
  131.    a subroutine invocation.  If it is not, return 0. */
  132.  
  133. #define ASM_INSN_IS_CALL(ASM_INSN) (strncmp ((ASM_INSN), "call .", 6) \
  134.                     ? 0 : (ASM_INSN) + 5)
  135.  
  136.  
  137.  
  138. /* Produce the schema corresponding the the standard function prologue
  139.    and epilogue.  Record values that are need upon function entry. */
  140.  
  141. #define SCHEMA_PROLOGUE(RECORD_REG_ON_ENTRY)            \
  142. {                                \
  143.   /* Code from FUNCTION_PROLOGUE: */                \
  144.   extern char call_used_regs[];                    \
  145.   extern int frame_pointer_needed;                \
  146.   extern rtx stack_pointer_rtx, frame_pointer_rtx;        \
  147.   int n_fregs = 0, i;                        \
  148.   int n_iregs = 64;                        \
  149.   register int regno;                        \
  150.   int sp_schema_produced = 0, fp_schema_produced = 0;        \
  151.                                 \
  152.   for (i = 32; i < FIRST_PSEUDO_REGISTER; i++)            \
  153.     if (regs_ever_live[i] && ! call_used_regs[i])        \
  154.       n_fregs++;                        \
  155.   for (i = 16; i < 32; i++)                    \
  156.     if (regs_ever_live[i]) { n_iregs = 96; break; }        \
  157.                                 \
  158.   if (RECORD_REG_ON_ENTRY [STACK_POINTER_REGNUM])        \
  159.     sp_schema_produced = record_sp ();                \
  160.   if (RECORD_REG_ON_ENTRY [FRAME_POINTER_REGNUM])        \
  161.     fp_schema_produced = record_fp ();                \
  162.                                 \
  163.   if (n_fregs)                            \
  164.     {                                \
  165.       for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++)    \
  166.         if (regs_ever_live[i] && ! call_used_regs[i])        \
  167.           {                            \
  168.         if (!sp_schema_produced)                \
  169.           sp_schema_produced = record_sp ();        \
  170.         if (regs_ever_live[i+1] && ! call_used_regs[i+1])    \
  171.           {                            \
  172.         store_schema_int_offset (STACK_POINTER_REGNUM,    \
  173.                      n_iregs + 4 * n_fregs, 0); \
  174.         n_fregs += 2, i += 1;                \
  175.           }                            \
  176.         else                        \
  177.           store_schema_int_offset (STACK_POINTER_REGNUM,    \
  178.                        n_iregs + 4 * n_fregs++, 1); \
  179.           }                            \
  180.     }                                \
  181.   if (regs_ever_live[32])                    \
  182.     {                                \
  183.       if (!fp_schema_produced)                    \
  184.     fp_schema_produced = record_fp ();            \
  185.       store_schema_int_offset (FRAME_POINTER_REGNUM, -16, 0);    \
  186.       store_schema_int_offset (FRAME_POINTER_REGNUM, -12, 0);    \
  187.     }                                \
  188.                                 \
  189.   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++)    \
  190.     if (RECORD_REG_ON_ENTRY [regno])                \
  191.       if ((regno == STACK_POINTER_REGNUM && !sp_schema_produced)\
  192.       || (regno == FRAME_POINTER_REGNUM && !fp_schema_produced) \
  193.       || (regno != STACK_POINTER_REGNUM && regno != FRAME_POINTER_REGNUM))\
  194.       {                                \
  195.     unknown_def_schema (regno);                \
  196.     issue_event (gen_rtx (REG, Pmode, regno));        \
  197.       }                                \
  198. }
  199.  
  200.  
  201. #define SCHEMA_EPILOGUE()                    \
  202. {                                \
  203.   /* Code from FUNCTION_EPILOGUE: */                \
  204.   extern char call_used_regs[];                    \
  205.   extern int current_function_pretend_args_size;        \
  206.   int fsize = (((get_frame_size ()) + 7 - STARTING_FRAME_OFFSET)\
  207.            & -8);                        \
  208.   int actual_fsize;                        \
  209.   int n_fregs = 0, i;                        \
  210.   int n_iregs = 64;                        \
  211.                                 \
  212.   for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++)    \
  213.     if (regs_ever_live[i] && ! call_used_regs[i])        \
  214.       n_fregs++;                        \
  215.   for (i = 16; i < 32; i++)                    \
  216.     if (regs_ever_live[i]) { n_iregs = 96; break; }        \
  217.   actual_fsize = fsize + n_iregs + (n_fregs*4+7 & -8);        \
  218.   actual_fsize += current_function_pretend_args_size+7 & -8;    \
  219.   fsize += current_function_pretend_args_size+7 & -8;        \
  220.   if (n_fregs)                            \
  221.     {                                \
  222.       int base;                            \
  223.       int offset;                        \
  224.       if (fsize < 4096)                        \
  225.     {                            \
  226.       base = FRAME_POINTER_REGNUM;                \
  227.       offset = n_iregs - actual_fsize;            \
  228.     }                            \
  229.       else                            \
  230.     {                            \
  231.       base = 1;        /* %g1 */            \
  232.       offset = n_iregs;                    \
  233.     }                            \
  234.       for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++)    \
  235.     if (regs_ever_live[i] && ! call_used_regs[i])        \
  236.       {                            \
  237.         if (regs_ever_live[i+1] && ! call_used_regs[i+1])    \
  238.           {                            \
  239.         load_schema_int_offset (base, offset + 4 * n_fregs, 0); \
  240.         n_fregs += 2, i += 1;                \
  241.           }                            \
  242.         else                        \
  243.           load_schema_int_offset (base, offset + 4 * n_fregs++, 1);\
  244.       }                            \
  245.     }                                \
  246. }
  247.  
  248.  
  249.  
  250. /* Produce and write the the assembly output file code to record the
  251.    various types of events. */
  252.  
  253.  
  254. /* Check that the AE buffer has SIZE bytes free.  If not, empty the
  255.    buffer. */
  256.  
  257. #define GENERATE_SPACE_CHECK(COMMENT, SIZE)            \
  258. {                                \
  259.   rtx xops [2];                            \
  260.   rtx label =  gen_label_rtx ();                \
  261.   char buffer [256];                        \
  262.                                 \
  263.   xops [0] = ae_buffer_pointer;                    \
  264.   xops [1] = ae_buffer_end_pointer;                \
  265.   sprintf (buffer, "subcc %%0, %%1, %%%%g0\t! %s Event", COMMENT); \
  266.   output_asm_insn (buffer, xops);                \
  267.                                 \
  268.   xops [0] = label;                        \
  269.   output_asm_insn ("ble %l0", xops);                \
  270.   output_asm_insn ("nop");                    \
  271.                                 \
  272.   output_asm_insn ("call _ae_flush_buffer", xops);        \
  273.   output_asm_insn ("nop");                    \
  274.                                 \
  275.   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (label)); \
  276. }
  277.  
  278.  
  279. /* Generate an event to record VALUE (an rtx register). */
  280.  
  281. #define GENERATE_EVENT(VALUE)                    \
  282. {                                \
  283.   rtx xops [2];                            \
  284.                                 \
  285.   xops [0] = VALUE;                        \
  286.   output_asm_insn ("mov %0, %%g2", xops);            \
  287.   xops [0] = ae_buffer_pointer;                    \
  288.   /* Is there a better way to do an unaligned store on a SPARC? */ \
  289.   output_asm_insn ("stb %%g2, [3 + %0]", xops);            \
  290.   output_asm_insn ("srl %%g2, 8, %%g2", xops);            \
  291.   output_asm_insn ("stb %%g2, [2 + %0]", xops);            \
  292.   output_asm_insn ("srl %%g2, 8, %%g2", xops);            \
  293.   output_asm_insn ("stb %%g2, [1 + %0]", xops);            \
  294.   output_asm_insn ("srl %%g2, 8, %%g2", xops);            \
  295.   output_asm_insn ("stb %%g2, [0 + %0]", xops);            \
  296.                                 \
  297.   xops [0] = ae_buffer_pointer;                    \
  298.   output_asm_insn ("add %0, 4, %0\t\t! End Event", xops);    \
  299. }
  300.  
  301.  
  302. /* Generate an event to record the integer VALUE, which should be
  303.    stored in BYTES bytes. */
  304.  
  305. #define GENERATE_SHORT_EVENT(VALUE, BYTES)            \
  306. {                                \
  307.   xops [0] = gen_rtx (CONST_INT, VOIDmode, VALUE);        \
  308.   output_asm_insn ("mov %0, %%g2", xops);            \
  309.                                 \
  310.   xops [0] = ae_buffer_pointer;                    \
  311.   if (BYTES == 1)                        \
  312.     output_asm_insn ("stb %%g2, [0 + %0]", xops);        \
  313.   else                                \
  314.     {                                \
  315.       output_asm_insn ("stb %%g2, [1 + %0]", xops);        \
  316.       output_asm_insn ("srl %%g2, 8, %%g2", xops);        \
  317.       output_asm_insn ("stb %%g2, [0 + %0]", xops);        \
  318.     }                                \
  319.                                 \
  320.   xops [0] = ae_buffer_pointer;                    \
  321.   xops [1] = gen_rtx (CONST_INT, VOIDmode, BYTES);        \
  322.   output_asm_insn ("add %0, %1, %0\t\t! End Short Event", xops); \
  323. }
  324.  
  325.  
  326. /* Generate an event to record ADDRESS, which is made computed from BASE and
  327.    OFFSET. */
  328.  
  329. #define GENERATE_ADDRESS_EVENT(ADDRESS, BASE, OFFSET)        \
  330. {                                \
  331.   rtx xops [2];                            \
  332.                                 \
  333.   xops [0] = BASE;                        \
  334.   output_asm_insn ("sethi %%hi(%0), %%g2", xops);        \
  335.   if (OFFSET != NULL)                        \
  336.     {                                \
  337.       xops [1] = OFFSET;                    \
  338.       output_asm_insn ("add %%g2, %%lo(%0)+%a1, %%g2", xops);    \
  339.     }                                \
  340.   else                                \
  341.     output_asm_insn ("add %%g2, %%lo(%0), %%g2", xops);        \
  342.                                 \
  343.   xops [0] = ae_buffer_pointer;                    \
  344.   /* Is there a better way to do an unaligned store on a SPARC? */ \
  345.   output_asm_insn ("stb %%g2, [3 + %0]", xops);            \
  346.   output_asm_insn ("srl %%g2, 8, %%g2", xops);            \
  347.   output_asm_insn ("stb %%g2, [2 + %0]", xops);            \
  348.   output_asm_insn ("srl %%g2, 8, %%g2", xops);            \
  349.   output_asm_insn ("stb %%g2, [1 + %0]", xops);            \
  350.   output_asm_insn ("srl %%g2, 8, %%g2", xops);            \
  351.   output_asm_insn ("stb %%g2, [0 + %0]", xops);            \
  352.                                 \
  353.   xops [0] = ae_buffer_pointer;                    \
  354.   output_asm_insn ("add %0, 4, %0\t\t! End Address Event", xops); \
  355. }
  356.  
  357.  
  358.  
  359. /* Assembly code routines for aecrt0.o. */
  360.  
  361. #ifdef AE_START_ASM
  362.     .text
  363.     .align 4
  364.     .global _ae_start
  365.     .proc 1
  366. _ae_start:
  367.     mov        0, %fp
  368.     ld         [%sp + 64], %l0
  369.     add        %sp, 68, %l1
  370.     sll        %l0, 2, %l2
  371.     add        %l2, 4, %l2
  372.     add        %l1, %l2, %l2
  373.     sethi      %hi(_environ), %l3
  374.     st         %l2, [%l3 + %lo(_environ)]
  375.     call    _ae_initialize    ! Addition
  376.     nop
  377.     mov    %o0, %sp    ! ditto
  378.     mov    %l0, %o0    ! ditto
  379.     mov    %l1, %o1    ! ditto
  380.     mov    %l2, %o2    ! ditto
  381.     call       _main
  382.     sub    %sp, 0x20, %sp
  383.     call       _exit
  384.     nop
  385.     call       __exit
  386.     nop
  387. #endif
  388.  
  389.  
  390. #ifdef AE_FLUSH_BUFFER_ASM
  391.     .text
  392.     .align 4
  393.     .global _ae_flush_buffer
  394.     .proc 1
  395. _ae_flush_buffer:
  396.     !#PROLOGUE# 0
  397.     save %sp,-240,%sp
  398.     !#PROLOGUE# 1
  399.     st %g1,[%fp-144]
  400.     st %g2,[%fp-148]
  401.     st %g3,[%fp-156]
  402.     st %g5,[%fp-160]
  403.     st %g7,[%fp-164]
  404.     sethi %hi(_ae_buffer_base),%g1
  405.     ld    [%g1+%lo(_ae_buffer_base)],%o2
  406.     sethi %hi(_ae_fd),%g1
  407.     ld    [%g1+%lo(_ae_fd)],%o0
  408.     mov %o2,%o1
  409.     call _write,0
  410.     sub %g4,%o2,%o2
  411.     sethi %hi(_ae_buffer_base),%g1
  412.     ld    [%g1+%lo(_ae_buffer_base)],%g4
  413.     sethi %hi(1048572),%g1
  414.     or %lo(1048572),%g1,%g1
  415.     add %g4,%g1,%g6
  416.     ld [%fp-144], %g1
  417.     ld [%fp-148], %g2
  418.     ld [%fp-156], %g3
  419.     ld [%fp-160], %g5
  420.     ld [%fp-164], %g7
  421.     ret
  422.     restore
  423.     .global _ae_fd
  424.     .common _ae_fd,8,"bss"
  425.     .global _ae_buffer_base
  426.     .common _ae_buffer_base,8,"bss"
  427. #endif
  428.  
  429.  
  430.  
  431. /* Definitions for AEC. */
  432.  
  433. /* a.out file format is BSD, with the nlist library to find symbols. */
  434.  
  435. #undef ECOFF_AOUT
  436.  
  437. #define BSD_AOUT
  438.  
  439.  
  440. /* Function call returns this many bytes after call instruction. */
  441.  
  442. #define PC_OFFSET_AFTER_CALL 8
  443.  
  444.  
  445. /* Return non-zero if register N is local to a function, e.g. can
  446.    have distinct values in different functions. */
  447.  
  448. #define REG_LOCAL_TO_FUNCTION(N) ((N) >=8 && (N) <= 31)
  449.  
  450.  
  451. /* Initialize registers before the generation program begins. */
  452.  
  453. #define INITIALIZE_REGISTERS() {output_set_value (0, "0");}
  454.